package com.zzyl.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.dto.NursingProjectDto;
import com.zzyl.entity.NursingProject;
import com.zzyl.entity.NursingProjectPlan;
import com.zzyl.mapper.NursingProjectMapper;
import com.zzyl.mapper.NursingProjectPlanMapper;
import com.zzyl.service.NursingProjectService;
import com.zzyl.vo.NursingProjectVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 护理项目Service实现类
 */
@Service
public class NursingProjectServiceImpl implements NursingProjectService {

    @Autowired
    private NursingProjectMapper nursingProjectMapper;

    @Autowired
    private NursingProjectPlanMapper nursingProjectPlanMapper;

    @Override
    public void add(NursingProjectDto nursingProjectDTO) {
        NursingProject nursingProject = new NursingProject();
        BeanUtils.copyProperties(nursingProjectDTO, nursingProject); // 将DTO对象属性拷贝到nursingProject中
        nursingProjectMapper.insert(nursingProject);
    }

    @Override
    public NursingProjectVo getById(Long id) {
        NursingProject nursingProject = nursingProjectMapper.selectById(id);
        NursingProjectVo nursingProjectVO = new NursingProjectVo();
        BeanUtils.copyProperties(nursingProject, nursingProjectVO);// 将nursingProject对象属性拷贝到nursingProjectVO中
        return nursingProjectVO;
    }

    /**
     * 分页查询护理项目列表
     * 获取每个护理项目关联的护理计划数量
     * 返回一个包含 NursingProjectVo 对象的 PageResponse 分页响应
     *
     * @param name     护理项目名称
     * @param status   状态：0-禁用，1-启用
     * @param pageNum  当前页码
     * @param pageSize 每页显示数量
     * @return 护理项目列表
     */
    @Override
    public PageResponse<NursingProjectVo> getByPage(String name, Integer status, Integer pageNum, Integer pageSize) {

        // 1、分页查询护理项目
        // 设置分页参数
        PageHelper.startPage(pageNum, pageSize);
        // 从数据库中查询护理项目分页数据
        Page<NursingProject> nursingProjects = nursingProjectMapper.selectByPage(name, status, pageNum, pageSize);
        // 将查询结果Page封装为分页响应对象PageResponse，并将 NursingProject(Po对象)转换为 NursingProjectVo (Vo对象) 类型
        // 两个转换：1）NursingProject(Po对象) -> NursingProjectVo(Vo对象)；2）Page -> PageResponse
        PageResponse<NursingProjectVo> projectVoPageResponse = PageResponse.of(nursingProjects, NursingProjectVo.class);

        // 2、获取并处理护理项目 ID，查询关联的护理计划数量（也就是该护理项目包含在几个护理计划中）
        // 从分页查询结果中获取护理项目的ids，并去重处理
        List<Long> ids = nursingProjects.getResult()
                .stream()
                .map(NursingProject::getId)
                .distinct() // 去重
                .collect(Collectors.toList()); // 转为list
        // 如果没有查询到护理项目，则直接返回分页响应对象
        if (CollUtil.isEmpty(ids)) {
            return projectVoPageResponse;
        }

        // 根据护理项目的id列表ids，从中间表(nursingProjectPlan)中查询所有与这些护理项目关联的护理计划
        // 一个护理项目可以在多个护理计划中，因此根据护理项目查询中间表会出现多个相同的护理计划
        List<NursingProjectPlan> projectPlanList = nursingProjectPlanMapper.listAllByProjectIds(ids);
        // 将查询到的护理计划按照护理计划所属的项目ID分组，生成一个Map
        // Map 的 key 是 projectId，value 是一个 List<NursingProjectPlan>，包含属于该项目的所有护理计划。
        // 分组后，通过护理项目 ID 直接从 Map 中获取到该项目的所有护理计划，而无需再次遍历整个查询出来的护理计划列表。
        Map<Long, List<NursingProjectPlan>> groupBy  = projectPlanList.stream()
                .collect(Collectors.groupingBy(NursingProjectPlan::getProjectId));

        // 遍历每一个 NursingProjectVo 对象，并为每个 NursingProjectVo 对象设置 count 属性
        // count表示该护理项目关联的护理计划数量
        projectVoPageResponse.getRecords().forEach(v ->
                v.setCount(
                        Optional.ofNullable(groupBy.get(v.getId())) // 获取当前项目 ID 对应的护理计划列表
                                .orElse(new ArrayList<>()) // 如果为空，则返回空列表
                                .size() // 计算护理计划数量
                )
        );

        // 返回最终构建好的 PageResponse<NursingProjectVo> 对象，
        // 其中包含了分页的 NursingProjectVo 列表，
        // 并且每个 NursingProjectVo 对象都包含了关联的护理计划数量。
        return projectVoPageResponse;
    }

    /**
     * 更新护理项目信息
     *
     * @param nursingProjectDTO 护理项目数据传输对象
     */
    @Override
    public void update(NursingProjectDto nursingProjectDTO) {
        NursingProject nursingProject = new NursingProject();
        BeanUtils.copyProperties(nursingProjectDTO, nursingProject);
        nursingProjectMapper.update(nursingProject);
    }

    /**
     * 删除护理项目信息
     *
     * @param id 护理项目编号
     */
    @Override
    public void deleteById(Long id) {
        nursingProjectMapper.deleteById(id);
    }

    /**
     * 启用或禁用
     * @param id ID
     * @param status 状态
     */
    @Override
    public void enableOrDisable(Long id, Integer status) {
        nursingProjectMapper.updateStatus(id, status);
    }

    /**
     * 查询所有护理项目
     * @return List<NursingProjectVo>
     */
    @Override
    public List<NursingProjectVo> listAll() {
        return nursingProjectMapper.listAll();
    }
}
